﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlClient;

using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.DataAccess.SqlDatabase;

using Fuse8.ContentManagementFramework.Domain;

namespace Fuse8.ContentManagementFramework.DataAccess.SqlAccess.Mappers
{
    internal class CmsWorkflowDataMapper : BaseSqlEntityDataMapper<CmsWorkflow, Guid>
    {
        private static BaseSqlEntityDataMapper<CmsWorkflow, Guid> _based = new BaseSqlEntityDataMapper<CmsWorkflow, Guid>(new string[] { "WorkflowHistory" });

        private static Dictionary<string, Func<object, IList<SqlParameter>>> _mappersTo = new Dictionary<string, Func<object, IList<SqlParameter>>>();

        static CmsWorkflowDataMapper()
        {
            _mappersTo.Add("cms_sp_WorkflowAdd",
                (p) =>
                {
                    return _based.MapTo("cms_sp_WorkflowAdd", p, true);
                });
            _mappersTo.Add("cms_sp_WorkflowSelectOne", (p) =>
            {
                return _based.MapTo("cms_sp_WorkflowSelectOne", p, false);
            });
        }

        public CmsWorkflowDataMapper()
            : base()
        { }

        public override IList<SqlParameter> MapTo(string sp, object parameter, bool isForCreate)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(parameter, "parameter");

            return _mappersTo.ContainsKey(sp) ?
                _mappersTo[sp](parameter) :
                _based.MapTo(sp, parameter, isForCreate);
        }

        public override CmsWorkflow MapFromMulti(string sp, SqlDataReader reader, CmsWorkflow stepEntity, int index)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(reader, "reader");

            if (index == 0)
            {
                stepEntity = new CmsWorkflow
                {
                    Id = reader.GetGuid(reader.GetOrdinal("WorkflowId")),
                    Cycle = reader.GetInt32(reader.GetOrdinal("Cycle")),
                    ApproveDateDeadline = !reader.IsDBNull(reader.GetOrdinal("ApproveDateDeadline")) ?
                       reader.GetDateTime(reader.GetOrdinal("ApproveDateDeadline")) :
                       new Nullable<DateTime>(),
                    ReviewDateDeadline = !reader.IsDBNull(reader.GetOrdinal("ReviewDateDeadline")) ?
                       reader.GetDateTime(reader.GetOrdinal("ReviewDateDeadline")) :
                       new Nullable<DateTime>(),
                    CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                    DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                    LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy")) ?
                        reader.GetInt32(reader.GetOrdinal("LastUpdatedBy")) :
                        new Nullable<int>(),
                    DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated")) ?
                       reader.GetDateTime(reader.GetOrdinal("DateLastUpdated")) :
                       new Nullable<DateTime>()
                };
            }
            else if (index == 1)
            {
                var stepWorkflowHistory = new CmsWorkflowHistory
                {
                    Id = reader.GetInt32(reader.GetOrdinal("WorkflowHistoryId")),
                    WorkflowId = reader.GetGuid(reader.GetOrdinal("WorkflowId")),
                    UserGroupId = !reader.IsDBNull(reader.GetOrdinal("UserGroupId")) ?
                       reader.GetInt32(reader.GetOrdinal("UserGroupId")) :
                       new Nullable<int>(),
                    UserId = !reader.IsDBNull(reader.GetOrdinal("UserId")) ?
                       reader.GetInt32(reader.GetOrdinal("UserId")) :
                       new Nullable<int>(),
                    WorkflowState = reader.GetInt32(reader.GetOrdinal("WorkflowState")),
                    WorkflowData = !reader.IsDBNull(reader.GetOrdinal("WorkflowData")) ?
                       reader.GetString(reader.GetOrdinal("WorkflowData")) :
                       null,
                    WorkflowDataType = !reader.IsDBNull(reader.GetOrdinal("WorkflowDataType")) ?
                        reader.GetString(reader.GetOrdinal("WorkflowDataType")) :
                        null,
                    IsLatestState = reader.GetBoolean(reader.GetOrdinal("IsLatestState")),
                    Notes = !reader.IsDBNull(reader.GetOrdinal("Notes")) ?
                        reader.GetString(reader.GetOrdinal("Notes")) :
                        null,
                    CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                    DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                    LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy")) ?
                        reader.GetInt32(reader.GetOrdinal("LastUpdatedBy")) :
                        new Nullable<int>(),
                    DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated")) ?
                       reader.GetDateTime(reader.GetOrdinal("DateLastUpdated")) :
                       new Nullable<DateTime>()
                };

                if (stepEntity.WorkflowHistory == null)
                {
                    stepEntity.WorkflowHistory = new CmsWorkflowHistory[] { stepWorkflowHistory };
                }
                else
                {
                    stepEntity.WorkflowHistory = stepEntity.WorkflowHistory.Concat(new CmsWorkflowHistory[] { stepWorkflowHistory }).ToList();
                }
            }
            else
            {
                throw new InvalidOperationException(string.Format("Stored procedure {0} can't return more than {1} result", sp, index));
            }

            return stepEntity;
        }
    }
}
